package utils

import (
	"fmt"
	"reflect"
	"strconv"
	"time"
)

// 总结： 通过v:=x.(type) 加switch case语句后，这里的v的类型就是case里面匹配到的类型的值，而在reflect放射里面通过 rv:=reflect.ValueOf(value) 后使用switch  rv.Kind()  然后case reflect.Xxx 语句后，我们如果需要获取对应的值，可以通过 Int , Uint, Float, Bool等大序列方法获取对应类型的值，如rv.Int(), rv.Float()等； 或者使用其他的类型函数进行转换， 如使用 strconv.Xxx 来进行类型转换。

// https://blog.csdn.net/tekin_cn/article/details/140627423
// x.(type) + switch case使用示例
// 将any类型的x转换为string类型
func ToString(x interface{}) string {
	// 通过 v := x.(type) 类型判断后，这里的 x 经过switch case后的 v 就是具体的类型的值。
	switch val := x.(type) {
	case int:
		return strconv.Itoa(val)
	case uint: // 注意这里的分支选择，如果要在里面使用强转，则这里只能有1个类型，不能是多个类型（如 case uint,uint8: 这样就不能使用类型强转）
		// 因为从这个分支进来，就可以明确了val是uint类型，这时就可以使用同大类型的强制转换了，即 uint64(val) 强转val为uint64类型
		return strconv.FormatUint(uint64(val), 10)
	case string:
		return val // 注意 这里的val就是 string类型的数据了
	case float64:
		// 这里的FormatFloat格式化，第一个参数val是float64类型的要格式化的数据，第二个参数就是我们的格式化符号，可选'e', 'E', 'f', 'g', 'G', 'x', and 'X'，第三个是小数点的长度。-1表示不限制，第4个参数是数据的位数（32或者64）
		return strconv.FormatFloat(val, 'f', -1, 64)
	case time.Time: //时间类型
		// Time类型的零值判断通过IsZero方法来完成，因为他的零值是很长的一个字符串“January 1, year 1, 00:00:00 UTC”
		if val.IsZero() {
			return ""
		}
		return val.String()
	default:
		// 不写了，直接来个大杀器,使用fmt.Sprintf转换为string
		return fmt.Sprintf("%v", val)
	}
}

// 使用放射获取reflect.Value对象后再使用 switch x.Kind()方法
// 加 case reflect.Xxx类型后 在调用大类型方法（如String, Int ,  Uint, Float, Bool等）
// 获取any对应的实际类型的值示例
func AnyToStr(value interface{}) string {
	// Indirect方法兼容指针或者值
	vrt := reflect.Indirect(reflect.ValueOf(value))
	switch vrt.Kind() {
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		return strconv.FormatInt(vrt.Int(), 10)
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		return strconv.FormatUint(vrt.Uint(), 10)
	case reflect.Float64:
		return strconv.FormatFloat(vrt.Float(), 'g', -1, 64)
	case reflect.Float32:
		return strconv.FormatFloat(vrt.Float(), 'g', -1, 32)
	case reflect.Bool:
		return strconv.FormatBool(vrt.Bool())
	default:
		// 使用%v 格式化为字符串返回
		return fmt.Sprintf("%v", vrt.Interface())
	}
}
